// 版权归 瞄你个汪 所有。使用本代码应遵守相关法律法规和Apache 2.0开源许可要求。
package top.geeke.toolkit.generator;

import cn.hutool.core.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;

/**
 * 代码生成
 * @author 瞄你个汪
 * @since 2024/5/25 17:18
 */
@Slf4j
public class AutoGenerator {
    private final VelocityEngine engine;
    private final VelocityContext context;
    private Template template;
    public AutoGenerator() {
        // 初始化模板引擎
        engine = new VelocityEngine();
        engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        engine.init();

        context = new VelocityContext();
    }

    /**
     * 创建代码生成器实例
     * @return 代码生成器
     */
    public static AutoGenerator create() {
        return new AutoGenerator();
    }

    /**
     * 设置模板
     * @param templatePath 模板路径
     */
    public AutoGenerator setTemplatePath(String templatePath) {
        template = engine.getTemplate(templatePath, StandardCharsets.UTF_8.name());
        return this;
    }

    /**
     * 设置作者、日期
     * @param author 作者
     * @param date 日期
     */
    public AutoGenerator setAuthorAndDate(String author, String date) {
        context.put("author", author);
        context.put("date", date);
        return this;
    }

    /**
     * 设置实体名称
     * @param packageRootName 包名
     * @param entityName 实体名
     * @param tableComment 表注释
     */
    public AutoGenerator setEntityInfo(String packageRootName, String entityName, String tableComment) {
        context.put("package", new HashMap<String,String>() {{
            put("Entity", packageRootName + ".entity");
            put("Mapper", packageRootName + ".mapper");
            put("Service", packageRootName + ".service");
            put("Controller", packageRootName + ".controller");
            put("Toolkit", packageRootName + ".toolkit.http.HttpResult");
        }});

        context.put("table", new HashMap<String,String>() {{
            put("entityName", entityName);
            put("comment", tableComment);
            put("moduleName", tableComment.replace("表", ""));
        }});
        return this;
    }

    /**
     * 设置API实体参数
     * @param apiInfo API信息
     */
    public AutoGenerator setEntityApiInfo(EntityApiInfo apiInfo) {
        BeanUtil.beanToMap(apiInfo).forEach(context::put);
        return this;
    }

    /**
     * 输出渲染后的数据到指定文件
     * @param filePath 路径
     */
    public void outputToFile(String filePath) {
        StringWriter writer = new StringWriter();
        template.merge(context, writer);

        // 输出到文件
        try {
            Path path = Paths.get(filePath);
            Files.createDirectories(path.getParent());
            Files.write(path, writer.toString().getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取渲染文本
     */
    public String renderText() {
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        return writer.toString();
    }
}
